import mxgraph from './graph/index';
import { Point, SysmlDiagramHelper, SysMLUtilHelper, UMLDIHelper } from 'src/api/sysml-imports';

import { getStyleObj, getImgPath, getStyleStr, isEmptyArr, getTextSize } from "src/util/common";
import { shapeApi } from "src/api/shape/shapeApi";
import { modelApi } from "src/api/model/modelApi";
import { ModelTreeDataGenerator } from "src/api/generator/model-tree-data-generator.js";

import treeUtil from 'src/components/ModelTree/treeUtil';
//// import { isReadOnlyMode } from 'src/util/readOnly';
import { behaviors } from './behaviors/index';
import { PropertyUtil } from 'src/components/Attribute/comps/PropertyUtil';
import ResizeUtil from './resizeUtil';
const {
  mxPoint,
  mxCell,
  mxGeometry,
  mxImage,
  mxConstants,
  mxUtils
} = mxgraph; 

const config = {
  //// 有nameLabel显示在外面的元素的typeName
  unExpandType: [
    "InitialNode", "ActivityFinalNode", "FlowFinalNode", "DecisionNode", "MergeNode", "ForkNodeHorizontal", "ForkNodeVertical", "JoinNodeHorizontal", "JoinNodeVertical", "TimeEventAction", //// 活动图
    "Actor", //// 用例图
    "PseudostateInitial", "FinalState", "ConnectionPointReference", "PseudostateDeepHistory", "PseudostateShallowHistory", "PseudostateJunction", "PseudostateForkVertical", "PseudostateForkHorizontal",
    "PseudostateChoice", "PseudostateJoinVertical", "PseudostateJoinHorizontal", "PseudostateEntryPoint", "PseudostateTerminate", "PseudostateExitPoint" //// 状态机
  ]
};
export const unExpandParentTypeNames = config.unExpandType;
export default {

  minShapePosition: { x: 4, y: 34 }, //// 除了diagram外的shape的最小x，y位置
  /**
   * 判断图形是否能与关系相连
   *
   * @param lineName
   * @param modelName
   * @param sourceName
   * @param targetName
   * @returns {boolean}
   */
  isConnectWithShape({ lineName: lineName, modelName: modelName, sourceName: sourceName, targetName: targetName }) {
    lineName = lineName.replace(/\s/g, '');
    if (configManager.getConnectConfig()[modelName] == null) return false;
    if (sourceName == null && targetName == null) {
      //// 只有lineName，即为选中关系时，对画布上每个model，判断Outgoing和Incoming是否包含该关系
      return ( app.activeProject.configManager.getConnectConfig()[modelName].outgoing.indexOf(lineName) > -1 ||  app.activeProject.configManager.getConnectConfig()[modelName].incoming.indexOf(lineName) > -1);
    } else if (sourceName != null && targetName == null) {
      //// 即当选中关系，且确定关系source后，判断model的Incoming是否包含该关系
      return  app.activeProject.configManager.getConnectConfig()[modelName].incoming.indexOf(lineName) > -1;
    } else if (sourceName == null && targetName != null) {
      //// 即当选中关系，且确定关系target后，判断model的Outgoing是否包含该关系
      return  app.activeProject.configManager.getConnectConfig()[modelName].outgoing.indexOf(lineName) > -1;
    }
  },

  /**
   * 向已有的泳道中插入泳道
   * @param {*} swimlanCell 当前点击的泳道cell
   * @param {*} position 插入位置 left/right/top/bottom
   */
  insertSwimlane(graph, swimlanCell, position){
    const point = { x: swimlanCell.umlShape.bounds.x, y: swimlanCell.umlShape.bounds.y };
    const parentShape = swimlanCell.parent.umlShape;
    const childs = swimlanCell.parent.umlShape.getUMLDiagramElements().toArray();
    const diagram = graph.diagram;
    if (position === 'left'){
      parentShape.bounds.x -= 200;
      parentShape.bounds.width += 200;
      //// point.x = swimlanCell.umlShape.bounds.x - 200;
      childs.forEach(shape => {
        if (shape.bounds.x >= swimlanCell.umlShape.bounds.x){
          shape.bounds.x += 200;

        }
      });

    } else if (position === 'right'){
      parentShape.bounds.width += 200;
      point.x = swimlanCell.umlShape.bounds.x + swimlanCell.umlShape.bounds.width;
      childs.forEach(shape => {
        if (shape.bounds.x > swimlanCell.umlShape.bounds.x){
          shape.bounds.x += 200;

        }
      });

    } else if (position === 'top'){
      parentShape.bounds.y -= 200;
      parentShape.bounds.height += 200;
      //// point.y = swimlanCell.umlShape.bounds.y - 200;
      childs.forEach(shape => {
        if (shape.bounds.y >= swimlanCell.umlShape.bounds.y){
          shape.bounds.y += 200;

        }
      });

    }
    else if (position === 'bottom'){
      parentShape.bounds.height += 200;
      point.y = swimlanCell.umlShape.bounds.y + swimlanCell.umlShape.bounds.height;
      childs.forEach(shape => {
        if (shape.bounds.y > swimlanCell.umlShape.bounds.y){
          shape.bounds.y += 200;

        }
      });

    }
    const res = this.post('/graph/shape/add', {
      typeName: swimlanCell.typeName,
      model: undefined,
      x: point.x,
      y: point.y,
      ownerShape: swimlanCell.parent.umlShape,
      diagram
    });
    if ( position === 'left' || position === "right"){
      res.data.umlShape.bounds.height = swimlanCell.geometry.height;

    } else {
      res.data.umlShape.bounds.width = swimlanCell.geometry.width;
    }
    if (parentShape.bounds.x < 4){
      parentShape.bounds.x = 4;
    }
    if (parentShape.bounds.y < 20){
      parentShape.bounds.y = 20;
    }
    if (parentShape.bounds.x + parentShape.bounds.width + 4 > diagram.bounds.width){
      diagram.bounds.width = parentShape.bounds.x + parentShape.bounds.width + 4;

    }
    if (parentShape.bounds.y + parentShape.bounds.height + 24 > diagram.bounds.height){
      diagram.bounds.height = parentShape.bounds.y + parentShape.bounds.height + 24;

    }

    app.$bus.emit('fresh-graph');
    app.$bus.emit('model-add', {});

  },

  //// ---------------------- 新的更新方式 -------------------
  /**
   * 根据umlShape创建cell
   * @param {*} umlShape
   * @param {*} option
   */
  createCellByUmlShape(umlShape, option){
    if (!umlShape.box.isVisible || umlShape.box.frontHidden) return;
    const isEdge = umlShape.box.position === 'edge';

    let geo;
    if (!umlShape.bounds) {  //// 线也有bounds，为0,0
      ResizeUtil.updateBoundsByBox(umlShape);
      console.warn('缺少bounds---自动创建bounds', umlShape);
      //// return;
    }

    if (isEdge) {
      geo =  new mxGeometry( 0, 0, 0, 0);

    } else {
  
      geo = new mxGeometry(umlShape.bounds.x, umlShape.bounds.y, umlShape.bounds.width, umlShape.bounds.height);
    }

    //// =  isEdge ? new mxGeometry( 0, 0, 0, 0) : new mxGeometry(umlShape.bounds.x, umlShape.bounds.y, umlShape.bounds.width, umlShape.bounds.height);

    //// if (umlShape.bounds && umlShape.bounds.offset){
    ////   geo.offset = umlShape.bounds.offset;
    //// }
    const isParentEdge =  umlShape.owner && umlShape.owner.box  && umlShape.owner.box.position === 'edge';
    if (umlShape.box.position === 'edgeLabel'){
      //// const p = umlShape.owningElement.waypoints.toArray()[0];
      geo.relative = true;
      geo.x = umlShape.bounds.x;
      geo.y = umlShape.bounds.y;
      const point = umlShape.bounds.offset || { x: 0, y: 0 };

      geo.offset = new mxPoint(point.x, point.y);

    }

    //// this.setShapeText(umlShape);
    this.setPortStyle(umlShape);

    const cell = new mxCell(
      umlShape.text,
      geo,
      umlShape.box.style
    );
    //// if (isReadOnlyMode()){
    ////   if (this.isMainShape(umlShape) ){
    ////     let styleArr = cell.style.split(';');
    ////     styleArr = styleArr.filter(i => !i.includes('fillColor'));
    ////     styleArr.push('fillColor=none');
    ////     cell.style = styleArr.join(';');
    ////   }
    //// }

    //// if (isParentEdge){
    ////   cell.style = cell.style.replace('movable=0;', '');
    //// }

    if (isEdge){
      cell.edge = true;
      cell.geometry.relative = true;
      if (umlShape.box.waypoints && umlShape.box.waypoints.length > 0){
        cell.geometry.points = umlShape.box.waypoints.map(point => new mxPoint(point.x, point.y));
      }
    } else {
      cell.vertex = true;
    }

    cell.setId(umlShape.id);
    cell.umlShape = umlShape;
    cell.relative = true;

    return cell;
  },

  /**
   * 根据umlShape创建cell并插入到Graph，会递归子元素
   * @param {*} graph
   * @param {*} umlShape
   * @param {*} option
   * @param {*} deep
   */

  addCellByUmlShape(graph, umlShape, option, deep = 1){
    graph.model.beginUpdate();
    try {
      const cell = this.createCellByUmlShape(umlShape, option);
      if (!cell) return;

      const parent = graph.model.getCell(umlShape.owner && umlShape.owner.id);

      if (cell.edge){

        //// 悬空线可能没有source或target
        const source = umlShape.sourceSingleLeaf && graph.model.cells[umlShape.sourceSingleLeaf.id];
        const target = umlShape.targetSingleLeaf && graph.model.cells[umlShape.targetSingleLeaf.id];
        cell.deep = 1;

        //// message 没有source的target但是会指定起始点
        //// if (edgeApi.getEdgeStart(umlShape) != null && edgeApi.getEdgeEnd(umlShape) != null){
        if (umlShape.box.sourcePoint){ //// 如果是悬空线
          let startPoint = umlShape.box.sourcePoint;
          let endPoint = umlShape.box.targetPoint;
          cell.geometry.setTerminalPoint(new mxPoint(startPoint.x, startPoint.y), true);
          cell.geometry.setTerminalPoint(new mxPoint(endPoint.x, endPoint.y), false);
          graph.addCell(cell, parent, undefined);
        } else {
          graph.addEdge(
            cell,
            parent,
            source,
            target,
          );
          console.log(cell);

        }

      } else {
        cell.deep = deep;
        graph.addCell(cell, parent, undefined);

      }
      let children = umlShape.children;
      if (isEmptyArr(children)) return;
      children = shapeApi.sortBySize(children);
      children.forEach(childUmlShape => {
        this.addCellByUmlShape(graph, childUmlShape, option, deep + 1);
      });
    } finally {
      graph.model.endUpdate();
    }
  },
  /**
   * 根据umlShape更新cell
   * @param {*} graph
   * @param {*} umlShape
   */
  updateCellByUmlShape(graph, umlShape) {
    const model = graph.getModel();
    const cell = model.getCell(umlShape.id);
    if (!cell ) {
      console.error('cell not found', umlShape.id);
      return;
    }
    const geo = cell.getGeometry();
    let newGeo;
    cell.umlShape = umlShape;
    //// if (umlShape.getTypeName() === 'BehaviorExecutionSpecification'){
    ////   debugger;
    //// }
    if (umlShape.bounds && (geo.x !== umlShape.bounds.x || geo.y !== umlShape.bounds.y || geo.height !== umlShape.bounds.height || geo.width !== umlShape.bounds.width)) {
      newGeo = geo.clone();

      newGeo.x = umlShape.bounds.x;
      newGeo.y = umlShape.bounds.y;
      newGeo.width = umlShape.bounds.width;
      newGeo.height = umlShape.bounds.height;
    }

    if (umlShape.bounds && umlShape.bounds.offset && geo.offset && ( umlShape.bounds.offset.x !== geo.offset.x || umlShape.bounds.offset.y !== geo.offset.y)){
      newGeo = newGeo || geo.clone();
      newGeo.offset = umlShape.bounds.offset;
    }

    this.setPortStyle(umlShape);

    if (umlShape.box.style !== cell.style) { 
      model.setStyle(cell, umlShape.box.style);
    }

    //// this.setShapeText(umlShape);
    if (umlShape._text !== cell.value) {
      console.log('text change');
      model.setValue(cell, umlShape._text);
    }
    
    //// 线的额外处理，如果shape.box.sourcePoint 不为null则当做悬空线处理，悬空线没有terminal（source和target），只有geo的sourcePoint和targetPoint
    if (cell.edge){
      if (cell.geometry.points && cell.geometry.points.length !== umlShape.box.waypoints.length){
        newGeo = newGeo || geo.clone();
        newGeo.points = umlShape.box.waypoints.map(point => new mxPoint(point.x, point.y));
      }

      if (umlShape.box.sourcePoint){ //// 如果是悬空线
        let start = umlShape.box.sourcePoint;
        let end = umlShape.box.targetPoint;
        
        if (start.x != geo.sourcePoint.x || start.y != geo.sourcePoint.y || end.x != geo.targetPoint.x || end.y != geo.targetPoint.y ){
          newGeo = newGeo || geo.clone();
          newGeo.sourcePoint.x = start.x;
          newGeo.sourcePoint.y = start.y;
          newGeo.targetPoint.x = end.x;
          newGeo.targetPoint.y = end.y;
        }

      } else { //// 非悬空线
        if (umlShape.sourceSingleLeaf && umlShape.targetSingleLeaf){
          const sourceShape = umlShape.sourceSingleLeaf;
          const targetShape = umlShape.targetSingleLeaf;
          if ((cell.source && cell.source.id) !== sourceShape.id) {
            model.setTerminal(cell, model.getCell(sourceShape.id), true);
          }
          if ((cell.target && cell.target.id) !== targetShape.id) {
            model.setTerminal(cell, model.getCell(targetShape.id), false);
          }
        }

      }

    }
    if (newGeo) {
      model.setGeometry(cell, newGeo);

    }
    //// if (geo.sourcePoint != null &&  geo.targetPoint != null ){
    ////   let start = edgeApi.getEdgeStart(umlShape);
    ////   let end = edgeApi.getEdgeEnd(umlShape);
    ////   if (start.x != geo.sourcePoint.x || start.y != geo.sourcePoint.y || end.x != geo.targetPoint.x || end.y != geo.targetPoint.y ){
    ////     newGeo = geo.clone();
    ////     newGeo.sourcePoint.x = start.x;
    ////     newGeo.sourcePoint.y = start.y;
    ////     newGeo.targetPoint.x = end.x;
    ////     newGeo.targetPoint.y = end.y;
    ////   }

    //// }
    //// if (cell.edge && umlShape.sourceSingleLeaf && umlShape.targetSingleLeaf){
    ////   const sourceShape = umlShape.sourceSingleLeaf;
    ////   const targetShape = umlShape.targetSingleLeaf;
    ////   if ((cell.source && cell.source.id) !== sourceShape.id) {
    ////     model.setTerminal(cell, model.getCell(sourceShape.id), true);
    ////   }
    ////   if ((cell.target && cell.target.id) !== targetShape.id) {
    ////     model.setTerminal(cell, model.getCell(targetShape.id), false);
    ////   }
    //// }

  },
  setPortStyle(umlShape){
    if (!umlShape.box.style.startsWith('shape=arrowPort;')) return;

    const styleObj = getStyleObj(umlShape.box.style);
    console.log(umlShape);
    const arrowType = this.getPortArrowType(umlShape.container);

    if (arrowType !== styleObj.arrowType){
      styleObj.arrowType = arrowType;
      umlShape.box.style = getStyleStr(styleObj);
    }
    if (!umlShape.box.portPosition){
      umlShape.box.portPosition = 'top';
    }
  },
  getPortArrowType(graphNode){
    const typeName = graphNode.getTypeName();
    if (typeName === 'InputPin'){
      return 'in';
    } else if (typeName === 'OutputPin') {
      return 'out';
    } else if (typeName === 'ProxyPort') {
      return PropertyUtil.getNodePropertyValue(graphNode, '方向');
    }
    let value = PropertyUtil.getNodePropertyValue(graphNode, 'direction');
    const  index = value.lastIndexOf('::') + 2;
    value = value.substr(index);

    //// value = in，out，inout
    //// const isGonge = PropertyUtil.getNodePropertyValue(graphNode, '共轭');
    //// if (isGonge){
    ////   if (value === 'in'){
    ////     value = 'out';
    ////   } else if (value === 'out'){
    ////     value = 'in';
    ////   }
    //// }
    //// SysML::Ports&Flows::FlowDirection::inout
    console.log('direction value', value, graphNode);
    return value;

    //// let appliedStereotypes = model.getAppliedStereotypes();
    //// let arrowType = 'none';
    //// if (appliedStereotypes && appliedStereotypes.size > 0) {

    ////   const direction = appliedStereotypes.toArray()[0].direction;
    ////   if (direction) {
    ////     arrowType = direction.toString();
    ////   }
    //// }
    //// return arrowType;

  },
  showInnerPackage(umlShape, diagram){

    const childShapes = umlShape.umlDiagramElement.toArray();
    const childCompartmentShapes = childShapes.filter(shape => SysMLUtilHelper.isCompartmentShape(shape));
    //// 如果原来就有compartment则先删除
    if (childCompartmentShapes.length){
      childCompartmentShapes.forEach(shape => {
        this.post('/graph/shape/delete', { shape, diagram: this.graph.diagram });

      });

    }
    //// 创建compartmentShape
    const list =  SysMLUtilHelper.createIconCompartmentShape(umlShape);

    const compShapeList = list.toArray();

    let compY = 50;
    compShapeList.forEach(shape => {

      //// 设置图片
      const imgShape = shape.umlDiagramElement.toArray()[0];
      const styleObj = getStyleObj(imgShape.localStyle.styles);
      styleObj.image = getImgPath(imgShape.localStyle.shapeType);
      const styleStr = getStyleStr(styleObj);
      const bounds = shape.bounds;

      this.post('/graph/shape/update', { typeName: shapeApi.getTypeNameByUmlShape(imgShape), diagram, oldShape: imgShape, styles: styleStr });
      this.post('/graph/shape/update', { typeName: shapeApi.getTypeNameByUmlShape(shape), diagram, oldShape: shape, bounds: { x: 10, y: compY, width: bounds.width, height: bounds.height } });
      compY += bounds.height;

    });
    const outShapeBounds = umlShape.bounds;
    if (compY + 12 > outShapeBounds.height){
      this.post('/graph/shape/update', { typeName: shapeApi.getTypeNameByUmlShape(umlShape), diagram, oldShape: umlShape, bounds: { x: outShapeBounds.x, y: outShapeBounds.y, width: outShapeBounds.width, height: compY + 12 } });
    }
    //// this.$bus.emit('fresh-graph');

  },
  showRelationshipLine(umlShape, diagram){
    //// this.$bus.emit('fresh-graph');
  },
  /**
   *根据umlShapes 批量更新cell,recurse可以控制是否递归更新子元素
   * @param {Object} graph
   * @param {Array<UmlShape>} umlShapes
   * @param {Boolean} recurse 是否递归更新子元素
   */
  updateCellsByUmlShapes(graph, umlShapes, recurse){
    umlShapes.forEach(umlShape => {
      if (!umlShape.box.isVisible || umlShape.box.frontHidden) return;
      this.updateCellByUmlShape(graph, umlShape);
      if (recurse && umlShape._cachedChildren){
        this.updateCellsByUmlShapes(graph, umlShape._cachedChildren, recurse);
      }
    });

  },
  /**
   * 根据cellId删除cell，cellId就是umlShape的Id
   * @param {*} graph
   * @param {*} ids
   */
  deleteCellByIds(graph, ids) {
    const model = graph.getModel();
    ids.forEach(id => {
      const cell = model.getCell(id);
      if (cell) {
        model.remove(cell);

      }
    });
    //// 	todo 也可以考虑使用 graph.removeCells
  },
  /**
   * 获取一个diagram下的所有Edge
   * @param {*} diagram
   * @param {*} result
   */
  getEdgeShapesByDiagram(diagram, result = []){
    let umlShapes = diagram.getUMLDiagramElements().toArray();
    umlShapes.forEach(shape => {
      shape.sourceEdges.toArray().forEach(edg => {
        result.push(edg);

      });
      const children = shape.umlDiagramElement.toArray();
      if (children.length){
        this.getEdgeShapesByDiagram(shape, result);
      }
    });
    return result;

  },
  getModelElementType (diagram) {
    if (diagram === null || typeof diagram === "undefined") {
      return 'Default type';
    }
    let owner = diagram.getModelElements().toArray()[0];
    if (SysMLUtilHelper.isModel(owner)) {
      return 'Model';
    } else if (SysMLUtilHelper.isPackage(owner)) {
      return 'Package';
    } else if (SysMLUtilHelper.isModelLibrary(owner)) {
      return 'ModelLibrary';
    } else if (SysMLUtilHelper.isView(owner)) {
      return 'View';
    } else if (SysMLUtilHelper.isProfile(owner)) {
      return 'Profile';
    } else if (SysMLUtilHelper.isConstraintBlock(owner)) {
      return 'ConstraintBlock';
    } else if (SysMLUtilHelper.isBlock(owner)) {
      return 'Block';
    } else if (SysMLUtilHelper.isRequirement(owner)) {
      return 'Requirement';
    } else if (SysMLUtilHelper.isActivity(owner)) {
      return 'Activity';
    } else if (SysMLUtilHelper.isStateMachine(owner)) {
      return 'StateMachine';
    } else if (SysMLUtilHelper.isInteraction(owner)) {
      return 'Interaction';
    } else {
      return 'Default type';
    }
  },
  getModelElementName (diagram) {
    if (diagram === null || typeof diagram === "undefined") {
      return 'Default name';
    }
    let context = diagram.getModelElements().toArray()[0];

    return context == null ? "" : context.getName();
  },
  getDiagramTitle(diagram){
    console.log(diagram);
    if (diagram.getModelElements().toArray().length > 0){
      const diagramTypeName = modelApi.getDiagramTypeName(diagram);
      const elementType = this.getModelElementType(diagram);
      const modelName = this.getModelElementName(diagram);
      const diagramName = diagram.getName() || '';
      return `${diagramTypeName}&nbsp;&nbsp;&nbsp;&nbsp;[ ${elementType} ]&nbsp;${modelName} [${diagramName}]`;
    } else {
      return "";
    }
  },

  /**
   * 根据鼠标event的位置获取该点相对某个cell的位置
   * @param {*} x 鼠标事件的clientX
   * @param {*} y 鼠标事件的clientY
   * @param {*} cell 目标cell
   */
  getRelativePoint(graph, cell, x, y){

    const graphCon = graph.container;
    const absGeo = { x: 0, y: 0 };

    let geo = cell.geometry;
    while (geo) {
      absGeo.y += geo.y;
      absGeo.x += geo.x;
      geo = cell.parent.geometry;
      cell = cell.parent;
    }
    const rect = graphCon.getBoundingClientRect();

    const relativeY = (y - rect.top - ((absGeo.y + graph.view.translate.y) * graph.view.scale  - graphCon.scrollTop)) / graph.view.scale;
    const relativeX = (x - rect.left  - ((absGeo.x + graph.view.translate.x) * graph.view.scale  - graphCon.scrollLeft)) / graph.view.scale;

    return { x: relativeX, y: relativeY };

  },
  //// 获取
  getCellAbsPoint(){

  },
  /**
   * parent是否是cell的祖先
   * @param {mxCell} parent
   * @param {mxCell} cell
   */
  isAncestor(parent, cell){
    let curParent = cell.parent;
    while (curParent && curParent.deep >= 0){
      if (parent === curParent) return true;
      curParent = curParent.parent;
    }
    return false;
  },

  /**
   * parent是否是cell的祖先
   * @param {mxCell} parent
   * @param {mxCell} cell
   */
  isAncestorGraphNode(parentNode, childNode){

    let curParent = childNode.container;
    while (curParent){
      if (parentNode.id === curParent.id) return true;
      curParent = curParent.container;
    }
    return false;
  },

  /**
   *
   * @param {*} cell
   */
  getMainCell(cell){
    while (cell && cell.umlShape) {

      if (this.isMainShape(cell.umlShape)
      //// || (edgeApi.isEdgeShape({ typeName: cell.typeName }) &&  !edgeApi.isEdgeShape({ typeName: cell.parent.typeName }))
      ) {
        return cell;
      } else {
        cell = cell.parent;

      }
    }

  },
  getMainShape(shape){
    while (shape) {

      if (this.isMainShape(shape)) {
        return shape;
      } else {
        shape = shape.owner;

      }
    }

  },
  getFirstNotInitMainShape(shape){
    while (shape ) {
      if (this.isMainShape(shape) && shape.box.boxX !== null && shape.box.position === 'absolute') {
        return shape;
      } else {
        shape = shape.owner;

      }
    }

  },
  isMainShape(umlShape){
    if (!umlShape.owner || !umlShape.owner.container || umlShape.owner.container.id !== umlShape.container.id) return true;
    else return false;
    //// return umlShape.localStyle && umlShape.box.style && umlShape.box.style.indexOf('isMainShape=1') > -1;
    //// return umlShape.isMainShape;
  },

  //// 判断是否可drop，在mxGraph的原型方法isValidDropTarget中被调用，此方法决定了拖动时是否高亮目标cell
  //// 修改移动后的parent, 在mxGraphHandler.prototype.moveCells 方法中修改parent
  isValidDropTarget(graph, cells, target){ //// 此处传入的cells已经被过滤过，都是movable=1的，有层级关系的元素是被铺开的
    //// console.log('22222222222', cells, target);
    //// 过滤掉子元素
    const ansCells = cells.filter(cell => {
      return !cells.find(ans => {
        return this.isAncestor(ans, cell);
      });
    });

    for (let i = 0; i < ansCells.length; i++){
      //// nameLabel和keywordLabel 不能改变parent
      if (SysMLUtilHelper.isUMLKeywordLabel(ansCells[i].umlShape) ) return false;
      //// 父元素不能放到子元素里
      if (this.isAncestor(ansCells[i], target)) return false;

      //// 如果target和当前parent相同则false
      if (ansCells[i].parent.id === target.id) return false;
      console.log(ansCells[i].parent.id === target.id);
      const shape = ansCells[i].umlShape;
      console.log('target.umlShape.getTypeName()', behaviors.get(target.umlShape.getTypeName()));
      const valid = behaviors.get(target.umlShape.getTypeName()).shapeHover(shape, target.umlShape, graph.diagramNode);
      if (!valid){
        return false;
      }
      //// if (ansCells[i].typeName){
      ////   if (!shapeApi.checkNest(ansCells[i].typeName, target.typeName)) {
      ////     return false;
      ////   }

      //// }
    }
    return true;

  },
  //// 判断模型元素是否可drop
  /**
   *
   * @param {*} element
   * @param {*} target
   */
  isValidDropTargetElement(element, target){
    //// 1.若拖动的是relationgroup，不做操作
    if (element === undefined || element === null || target === undefined || target === null){
      return false;
    }
    //// 2.若target为图，则不做操作
    if (ModelTreeDataGenerator.isDiagram(target)){
      return false;
    }
    //// 3.若元素为关系，或是target为关系，则不做操作
    if (ModelTreeDataGenerator.isRelation(element) || ModelTreeDataGenerator.isRelation(target)){
      return false;
    }
    //// 4.若目标元素为子节点，或是该元素原有父节点，则不做操作
    if (this.isAncestorElement(element, target) || (element.owningPackage && element.owningPackage.id === target.id)){
      return false;
    }
    //// 5.判断element拖拽到target中是否合法，后续修改
    //// 判断两者是否能存在父子关系
    let ename = modelApi.getModelTypeName(element);
    let tname = modelApi.getModelTypeName(target);
    if (ename) {
      if (!shapeApi.checkNest(ename, tname)) {
        return false;
      }
    }
    return true;
  },
  getTextHeight(text, styleStr, textWidth){

    const style = getStyleObj(styleStr);
    let dy = 0;
    dy += 2 * (style[mxConstants.STYLE_SPACING] || 0);
    dy += style[mxConstants.STYLE_SPACING_TOP] || 0;
    dy += style[mxConstants.STYLE_SPACING_BOTTOM] || 0;
    text = text.replace(/\n/g, '<br>');
    const fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;
    let size = mxUtils.getSizeForString(text || '1', fontSize,
      style[mxConstants.STYLE_FONTFAMILY], textWidth,
      style[mxConstants.STYLE_FONTSTYLE]);
    //// const width = size.width + dx;
    const height = size.height + dy + 4;
    return height;

  },
  getTextWidth(text, styleStr){
    const style = getStyleObj(styleStr);
    let dx = 0;
    dx += 2 * (style[mxConstants.STYLE_SPACING] || 0);
    dx += style[mxConstants.STYLE_SPACING_LEFT] || 0;
    dx += style[mxConstants.STYLE_SPACING_RIGHT] || 0;
    text = text.replace(/\n/g, '<br>');
    const fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;
    let size = mxUtils.getSizeForString(text || '1', fontSize,
      style[mxConstants.STYLE_FONTFAMILY]);
    //// const width = size.width + dx;
    const width = size.width + dx + 4;
    return width;
  },
  getTextSize(text, styleStr, textWidth){
    //// debugger;
    const textSizeCache =  app.activeGraphTab && app.activeGraphTab.textSizeCache;
    const key = text + '_' + styleStr + '_' + textWidth;
    if (textSizeCache && textSizeCache[key]) return { ...textSizeCache[key] };
    const style = getStyleObj(styleStr);
    //// text = text.replace(/\n/g, '<br>');
    const fontSize = style[mxConstants.STYLE_FONTSIZE] || mxConstants.DEFAULT_FONTSIZE;
    let size = getTextSize(text || '1', { fontSize, width: textWidth, fontFamily: style[mxConstants.STYLE_FONTFAMILY], whiteSpace: style.whiteSpace });
    size.width += 4;
    if (textSizeCache){
      textSizeCache[key] = size;
    }
    return size;

  },
  limitShapePosition(point, typeName){
    if ( typeName === 'ActivityParameterNode') return point;
    if ( point.x < this.minShapePosition.x) point.x = this.minShapePosition.x;
    if ( point.y < this.minShapePosition.y) point.y = this.minShapePosition.y;
    return point;
  },

  updateEdgeOwner(edgeShape, parentShape){
    if (edgeShape && parentShape){
      edgeShape.updateOwner(parentShape);

    }
   
  }

};
